<?php

Raise::load('core.RaiseDataType');
Raise::load('core.RaiseCollection');
Raise::load('core.RaiseNumericCollection');

/**
 * RaiseString class
 * represents a string and provides functionalities with respect to a string
 *
 * @author Sam-Mauris Yong <hellclanner at live dot com>
 * @license http://www.opensource.org/licenses/bsd-license New BSD License
 * @package Raise.Core.Text
 * @since 1.2
 */
class RaiseString extends RaiseDataType {

    /**
     * The internal value of this string
     * @var string
     */
    private $value = '';

    /**
     * Create a new RaiseString object
     * @param string|RaiseString $v 
     */
    function __construct($v) {
        if($v instanceof RaiseString){
            $v = $v->value();
        }
        $this->value($v);
    }

    /**
     * Get or set the value of the string
     * @param string $v (optional) Set the new value of the string
     * @return string
     */
    public function value($v = null) {
        if (func_num_args() == 1) {
            $this->value = $v;
        }
        return $this->value;
    }

    /**
     * Strip whitespace from the beginning and end of a string
     * @return RaiseString
     */
    public function trim() {
        return new RaiseString(trim($this->value()));
    }

    /**
     * Strip whitespace from the beginning and end of a string
     * @return RaiseString
     */
    public function trimLeft() {
        return new RaiseString(ltrim($this->value()));
    }

    /**
     * Strip whitespace from the beginning and end of a string
     * @return RaiseString
     */
    public function trimRight() {
        return new RaiseString(rtrim($this->value()));
    }

    /**
     * Split the string into several strings
     * @param RaiseString|string $c
     * @return RaiseTypedCollection 
     */
    public function split($c) {
        $strs = explode($c, $this->value());
        $r = new RaiseTypedCollection('RaiseString');
        foreach($strs as $s){
            $r->add(new RaiseString($s));
        }
        return $r;
    }

    /**
     * Replaces occurances of $a with $b in the string
     * @param RaiseString|array|RaiseCollection $a A string, or a collection of string, to be replaced
     * @param RaiseString|array|RaiseCollection $b A string, or a collection of string, to be the replacement
     * @param intgger $limit The maximum number of occurances to replace
     * @return RaiseString 
     */
    public function replace($a, $b, $limit = null) {
        if($a instanceof RaiseCollection){
            $a = $a->toArray();
        }
        if($b instanceof RaiseCollection){
            $b = $b->toArray();
        }
        if ($limit !== null) {
            return new RaiseString(str_replace($a, $b, $this->value(), $limit));
        } else {
            return new RaiseString(str_replace($a, $b, $this->value()));
        }
    }

    /**
     * Find the position of the first occurance of the string $s in the string
     * @param RaiseString|string $s The string to search for
     * @param integer $offset (optional) The position to start searching for
     * @return integer A non-negative number indicating the position of $s in the string, or -1 if not found. 
     */
    public function indexOf($s, $offset = 0) {
        if (!($s instanceof RaiseString)) {
            $s = new RaiseString($s);
        }
        $r = strpos($this->value(), $s->value(), $offset);
        if ($r === false) {
            return -1;
        }
        return $r;
    }

    /**
     * Find the position of the last occurance of the string $s in the string
     * @param RaiseString|string $s The string to search for
     * @param integer $offset (optional) The position to start searching for
     * @return integer A non-negative number indicating the position of $s in the string, or -1 if not found. 
     */
    public function lastIndexOf($s, $offset = 0) {
        if (!($s instanceof RaiseString)) {
            $s = new RaiseString($s);
        }
        $r = strrpos($this->value(), $s->value(), $offset);
        if ($r === false) {
            return -1;
        }
        return $r;
    }

    /**
     * Find all unique occurances of a substring in the string
     * @param RaiseString|string $s The substring to find occurances
     * @param integer $offset (optional) The position to start searching for
     * @return RaiseNumericCollection 
     */
    public function occurances($s, $offset = 0) {
        if (!($s instanceof RaiseString)) {
            $s = new RaiseString($s);
        }
        $occurances = new RaiseNumericCollection();
        while (($idx = $this->indexOf($s, $offset)) >= 0) {
            $occurances->add($idx);
            $offset = $idx + $s->length();
        }
        return $occurances;
    }

    /**
     * Fetch a part of the string
     * @param type $start The starting position of the string to fetch from
     * @param type $length (optional) The number of characters to fetch. If not specified, the method will fetch from start to the end of the string
     * @return RaiseString 
     */
    public function substring($start, $length = null) {
        if (func_num_args() == 2) {
            return new RaiseString(substr($this->value(), $start, $length));
        } else {
            return new RaiseString(substr($this->value(), $start));
        }
    }

    /**
     * Set all alphabets in the string to upper case
     * @return RaiseString 
     */
    public function toUpper() {
        return new RaiseString(strtoupper($this->value()));
    }

    /**
     * Set all alphabets in the string to lower case
     * @return RaiseString 
     */
    public function toLower() {
        return new RaiseString(strtolower($this->value()));
    }

    /**
     * Pad the left side of the string to the desired length
     * @param string $char The string used for padding
     * @param integer $length The maximum amount of characters for the string
     * @return RaiseString 
     */
    public function padLeft($char, $length) {
        return new RaiseString(str_pad($this->value(), $length, $char, STR_PAD_LEFT));
    }

    /**
     * Pad the right side of the string to the desired length
     * @param string $char The string used for padding
     * @param integer $length The maximum amount of characters for the string
     * @return RaiseString 
     */
    public function padRight($char, $length) {
        return new RaiseString(str_pad($this->value(), $length, $char, STR_PAD_RIGHT));
    }

    /**
     * Pad both sides of the string to the desired length equally
     * @param string $char The string used for padding
     * @param integer $length The maximum amount of characters for the string
     * @return RaiseString 
     */
    public function padBoth($char, $length) {
        return new RaiseString(str_pad($this->value(), $length, $char, STR_PAD_BOTH));
    }

    /**
     * Get the length of the string
     * @return integer
     */
    public function length() {
        return strlen($this->value());
    }

    public function __toString() {
        return $this->value();
    }

    public function equals($o) {
        return (($o instanceof RaiseString) && $this->value() == $o->value()) || (is_string($o) && $this->value == $o);
    }

}
